import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.Serializable;
import java.util.ArrayList;

import javax.swing.JPanel;

public class BangBean2 extends JPanel implements Serializable {
	private int xm, ym;
	private int cSize = 20; // Circle size
	private String text = "Bang!";
	private int fontSize = 48;
	private Color tColor = Color.red;
	private ArrayList<ActionListener> actionListeners = new ArrayList<ActionListener>();

	public BangBean2() {
		addMouseListener(new ML());
		addMouseMotionListener(new MM());
	}

	public synchronized int getCircleSize() {
		return cSize;
	}

	public synchronized void setCircleSize(int newSize) {
		cSize = newSize;
	}

	public synchronized String getBangText() {
		return text;
	}

	public synchronized void setBangText(String newText) {
		text = newText;
	}

	public synchronized int getFontSize() {
		return fontSize;
	}

	public synchronized void setFontSize(int newSize) {
		fontSize = newSize;
	}

	public synchronized Color getTextColor() {
		return tColor;
	}

	public synchronized void setTextColor(Color newColor) {
		tColor = newColor;
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.setColor(Color.black);
		g.drawOval(xm - cSize / 2, ym - cSize / 2, cSize, cSize);
	}

	// This is a multicast listener, which is
	// more typically used than the unicast
	// approach taken in BangBean.java:
	public synchronized void addActionListener(ActionListener l) {
		actionListeners.add(l);
	}

	public synchronized void removeActionListener(ActionListener l) {
		actionListeners.remove(l);
	}

	// Notice this isn't synchronized:
	@SuppressWarnings("unchecked")
	public void notifyListeners() {
		ActionEvent a = new ActionEvent(BangBean2.this,
				ActionEvent.ACTION_PERFORMED, null);
		ArrayList<ActionListener> lv = null;
		// Make a shallow copy of the List in case
		// someone adds a listener while we're
		// calling listeners:
		synchronized (this) {
			lv = (ArrayList<ActionListener>) actionListeners.clone();
		}
		// Call all the listener methods:
		for (int i = 0; i < lv.size(); i++)
			lv.get(i).actionPerformed(a);
	}

	class ML extends MouseAdapter {
		public void mousePressed(MouseEvent e) {
			Graphics g = getGraphics();
			g.setColor(tColor);
			g.setFont(new Font("TimesRoman", Font.BOLD, fontSize));
			int width = g.getFontMetrics().stringWidth(text);
			g.drawString(text, (getSize().width - width) / 2,
					getSize().height / 2);
			g.dispose();
			notifyListeners();
		}
	}

	class MM extends MouseMotionAdapter {
		public void mouseMoved(MouseEvent e) {
			xm = e.getX();
			ym = e.getY();
			repaint();
		}
	}

	public static void main(String[] args) {
		BangBean2 bb = new BangBean2();
		bb.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.out.println("ActionEvent" + e);
			}
		});
		bb.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.out.println("BangBean2 action");
			}
		});
		bb.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.out.println("More action");
			}
		});
		Console.run(bb, 300, 300);
	}
} // /:~
